#include "tunnel.h"

#include <malloc.h>
#include <stdio.h>
#include <sys/resource.h>
#include <unistd.h>

using namespace yhaida;
using std::string;

EventLoop *g_eventLoop;
InetAddress *g_serverAddr;
std::map<string, TunnelPtr> g_tunnels;

void onServerConnection(const TcpConnectionPtr &conn)
{
    LOG_DEBUG << (conn->connected() ? "UP" : "DOWN");
    if (conn->connected())
    {
        conn->setTcpNoDelay(true);
        conn->stopRead(); //在连接期间不接受信息
        TunnelPtr tunnel(new Tunnel(g_eventLoop, *g_serverAddr, conn));
        tunnel->setup();   //初始化
        tunnel->connect(); //开始代理连接客户端
        g_tunnels[conn->name()] = tunnel;
    }
    else
    {
        assert(g_tunnels.find(conn->name()) != g_tunnels.end());
        g_tunnels[conn->name()]->disconnect(); //断开连接
        g_tunnels.erase(conn->name());
    }
}

void onServerMessage(const TcpConnectionPtr &conn,
               Buffer *buffer,
               Timestamp)
{
    LOG_DEBUG << buffer->readableBytes();
    if (!conn->getContext().empty())
    {
        const TcpConnectionPtr &clientConn = boost::any_cast<const TcpConnectionPtr &>(conn->getContext());
        clientConn->send(buffer);
    }
}

void memstat()
{
// Arena 0://第一个arena（每个线程分配一个arena），这里只有一个线程
// system bytes     =     135168//本线程从操作系统获得的动态内存，这里是132KB
// in use bytes     =       1152//本线程在使用的动态内存，1152字节
// Total (incl. mmap)://总的使用情况，各个线程使用动态内存的累加值
// system bytes     =     135168//本进程从操作系统获得的动态内存，这里是132KB
// in use bytes     =       1152//本进程在使用的动态内存，1152字节
// max mmap regions =          0//当一次申请内存超过128KB（32位操作系统）或1MB（64位操作系统）时，会增加mmap区域，这里统计使用mmap区域的个数
// max mmap bytes   =          0//mmap区域对应内存大小
    malloc_stats(); //检查内存使用情况(printf)
}

int main(int argc, char *argv[])
{
    if (argc < 4)
    {
        fprintf(stderr, "Usage: %s <host_ip> <port> <listen_port>\n", argv[0]);
    }
    else
    {
        LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid();
        {
            // set max virtual memory to 256MB.
            size_t kOneMB = 1024 * 1024;
            rlimit rl = {256 * kOneMB, 256 * kOneMB};
            setrlimit(RLIMIT_AS, &rl);
        }
        const char *ip = argv[1];
        uint16_t port = static_cast<uint16_t>(atoi(argv[2]));
        InetAddress serverAddr(ip, port);
        g_serverAddr = &serverAddr;

        uint16_t acceptPort = static_cast<uint16_t>(atoi(argv[3]));
        InetAddress listenAddr(acceptPort);

        EventLoop loop;
        g_eventLoop = &loop;
        loop.runEvery(3, memstat);
        
        TcpServer server(&loop, listenAddr);
        server.setConnectionCallback(onServerConnection);
        server.setMessageCallback(onServerMessage);

        server.start();
        loop.loop();
    }
}
